#!/usr/bin/env python
#
# License: BSD
#   https://raw.github.com/robotics-in-concert/rocon_tools/license/LICENSE
#
##############################################################################
# Description
##############################################################################

"""
.. module:: roslaunch_configuration
   :platform: Unix
   :synopsis: Configuration for a single roslaunch


This module provides the context for a roslaunch configuration.

----

"""
##############################################################################
# Imports
##############################################################################

import os
import rocon_console.console as console
import rocon_python_utils
from urlparse import urlparse

from .exceptions import InvalidRoconLauncher

##############################################################################
# Methods
##############################################################################


def _get_default_port():
    '''
    Helper method to determine the default port to use for roslaunch
    configurations. Uses the ros master uri port or 11311 otherwise.

    :returns: the default port
    :rtype: int
    '''
    ros_master_port = urlparse(os.environ["ROS_MASTER_URI"]).port
    return ros_master_port if ros_master_port is not None else 11311

##############################################################################
# Classes
##############################################################################


class RosLaunchConfiguration(object):
    """
    Configuration for a roslaunch (to be later spawned inside a terminal).
    This is typically generated by reading from a rocon_launch xml file
    but is also usable by other sources wishing to spawn roslaunched
    terminals.
    """
    __slots__ = [
                 'package',
                 'name',
                 'title',
                 'namespace',
                 'port',
                 'options',
                 'args',
                 'path'
                ]

    default_port = _get_default_port()

    def __init__(self,
                 name,
                 package=None,
                 port=None,
                 title=None,
                 namespace=None,
                 args=[],
                 options=""):
        """
        :param str name: filename (must be absolute path if package is set to None)
        :param str package: name of the catkin package to find the launcher in (can be None)
        :param int port: port to launch on (defaults to ROS_MASTER_URI's or 11311 if None)
        :param str title: title to use for the launch window (provides a sensible default if None)
        :param str[] args: any args contained in the launcher
        :param str options: command line options to pass to roslaunch (string form, not list)

        :raises :exc:`.InvalidRoconLauncher`
        """
        self.args = args
        """A list of (name, value) tuples representing roslaunch args."""
        self.package = package
        """Package name in which to find the roslaunch (optional)."""
        self.name = name
        """Name of the roslauncher (must be absolute if there is no package specified)."""
        self.title = title or "RosLaunch Window"
        """The string to display on a spawned terminal window (easy for tabbing)."""
        self.namespace = namespace
        """Push the roslaunch down into this namespace."""
        self.path = None
        """The absolute path to this launcher (automatically derived from package/name)."""
        if self.package is None:
            # look for a standalone launcher
            if os.path.isfile(self.name):
                self.path = self.name
            else:
                raise InvalidRoconLauncher("roslaunch file does not exist [%s]" % self.name)
        else:
            # look for a catkin package launcher
            try:
                self.path = rocon_python_utils.ros.find_resource(self.package, self.name)
            except IOError as e:
                raise InvalidRoconLauncher("roslaunch file does not exist [%s/%s][%s]" % (self.package, self.name, str(e)))
        self.port = port or RosLaunchConfiguration.default_port
        """Port to start this configuration on (defaults to env. ROS_MASTER_URI or 11311 if not set)."""
        self.options = options
        """A string of options to pass to roslaunch (not a list!), e.g. '--screen --local'"""

    def __str__(self):
        s = console.bold + "Roslaunch Configuration" + console.reset + '\n'
        if self.package is not None:
            s += console.cyan + "  Package" + console.reset + "   : " + console.yellow + "%s" % self.package + console.reset + '\n'  # noqa
        s += console.cyan + "  Name" + console.reset + "      : " + console.yellow + "%s" % self.name + console.reset + '\n'  # noqa
        s += console.cyan + "  Port" + console.reset + "      : " + console.yellow + "%s" % str(self.port) + console.reset + '\n'  # noqa
        s += console.cyan + "  Title" + console.reset + "     : " + console.yellow + "%s" % self.title + console.reset + '\n'  # noqa
        s += console.cyan + "  Namespace" + console.reset + " : " + console.yellow + "%s" % self.namespace + console.reset + '\n'  # noqa
        s += console.cyan + "  Args" + console.reset + "      : " + console.yellow + "%s" % self.args + console.reset + '\n'  # noqa
        s += console.cyan + "  Options" + console.reset + "   : " + console.yellow + "%s" % self.options + console.reset + '\n'  # noqa
        return s

    def append_option(self, option):
        """
        Appends a roslaunch command line option to the configuration.

        :param str option:
        """
        self.options = self.options + " " + option

    def screen(self):
        """
        :returns: true or false depending on whether --screen is applied or not.
        :rtype: bool
        """
        return '--screen' in self.options
